/*
 * @Author: hujingyang
 * @Date: 2022-10-12 14:00:00
 * @Description:
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2022-11-28 16:26:46
 * @FilePath: \ks-cjhd-web\src\service\request\index.ts
 * @IDE: Created by VScode.
 */

import axios from "axios";
import type { AxiosInstance } from "axios";
import type {
  HJYRequestConfig,
  HJYRequestInterceptors,
} from "./interface.types";

import { ElLoading } from "element-plus";
import { LoadingInstance } from "element-plus/lib/components/loading/src/loading";
import { getSystemTime } from "../constant.apis";

const DEFAULT_LOADING = false;

class HJYRequest {
  instance: AxiosInstance;
  interceptors?: HJYRequestInterceptors;
  loading?: LoadingInstance;
  showLoading: boolean;

  constructor(config: HJYRequestConfig) {
    //创建axios实例
    this.instance = axios.create(config);

    this.instance.defaults.headers.get["Content-Type"] =
      "application/x-www-form-urlencoded;charset=UTF-8";
    this.instance.defaults.headers.post["Content-Type"] =
      "application/json;charset=UTF-8";

    //保存基本信息
    this.interceptors = config.interceptors;
    this.showLoading = config.showLoading ?? DEFAULT_LOADING;

    //请求拦截，先添加的后执行
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch
    );

    //响应拦截，先添加先响应
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptor,
      this.interceptors?.responseInterceptorCatch
    );

    //为所有实例添加拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // console.log("所有的实例都有拦截器：请求拦截成功", this.showLoading);

        if (this.showLoading) {
          //如果使用组件样式按需引入，需要单独引入ElLoading的样式文件，否则直接调用会出现样式问题
          this.loading = ElLoading.service({
            lock: true,
            text: "正在请求数据",
            background: "rgba(255,255,255,0.5)",
          });
        }

        return config;
      },
      (err) => {
        // console.log("所有的实例都有拦截器：请求拦截失败");
        return err;
      }
    );

    this.instance.interceptors.response.use(
      (config) => {
        // console.log("所有的实例都有拦截器：响应拦截成功");
        if (this.showLoading) setTimeout(() => this.loading?.close(), 250);
        return config;
      },
      (err) => {
        // console.log("所有的实例都有拦截器：请求拦截失败");
        if (this.showLoading) setTimeout(() => this.loading?.close(), 250);
        if (err.response.status === 404) console.log("404错误~");
        return err;
      }
    );
  }

  request<T>(config: HJYRequestConfig<T>): Promise<T> {
    //如果函数调用时，调用了拦截器，则使用用户传递的拦截逻辑
    if (config.interceptors?.requestInterceptor) {
      config = config.interceptors.requestInterceptor(config);
    }

    //是否开启页面loading
    if (config.showLoading) {
      this.showLoading = config.showLoading;
    }

    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res: any) => {
          //使用拦截器
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res);
          }
          //将页面loading设置为初始值
          this.showLoading = DEFAULT_LOADING;

          if (res.request.responseType !== "blob") {
            if (!res.data) res.data = { success: false };

            if (config.url !== getSystemTime[0]) {
              res.data.success = res.data?.code === 200 ? true : false;
            }
          }

          resolve(res.data);
        })
        .catch((err) => {
          //将页面loading设置为初始值
          this.showLoading = DEFAULT_LOADING;
          reject(err);
        });
    });
  }

  get<T>(config: HJYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: "GET" });
  }

  post<T>(config: HJYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: "POST" });
  }

  delete<T>(config: HJYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: "DELETE" });
  }

  patch<T>(config: HJYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: "PATCH" });
  }

  put<T>(config: HJYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: "PUT" });
  }
}

export default HJYRequest;
